#include "Headers/filethread.h"

FileThread::FileThread(QString ServerIp,QString UserName,QString ToUserName)
{
    this->ServerIp=ServerIp;
    this->UserName=UserName;
    this->ToUserName=ToUserName;
    m_downloadPath = QCoreApplication::applicationDirPath() + "/../File";
    QDir dir;
    if(!dir.exists(m_downloadPath)) {
        dir.mkdir(m_downloadPath);
    }
    is_dow = false;
    serverFile = new MyFileInfo();
}

void FileThread::FileSocketInit(){
    FileTcpPort=1113;
    FileTcpSocket = new QTcpSocket();
    FileTcpSocket->connectToHost(ServerIp,FileTcpPort);
    connect(FileTcpSocket, &QTcpSocket::connected, this, [=](){
        QByteArray data=(QString(R"({
                                 "Type":%1,
                                 "User":"%2"
                                 })").arg(JOIN_TYPE).arg(UserName)).toUtf8();
        FileTcpSocket->write(data);
        QThread::usleep(3); //添加延时，防止服务端发送文件帧过快，否则发送过快，客户端接收不过来，导致丢包
        //等待发送完成，才能继续下次发送，
        if(!FileTcpSocket->waitForBytesWritten(3*1000)) {
            qDebug()<<("网络请求超时");
            return;
        }
        qDebug()<<"JOIN OK!";
    });
    connect(FileTcpSocket, &QTcpSocket::readyRead, this, [=](){
        if(is_dow){fileDataRead(FileTcpSocket);return;}
        QString data = FileTcpSocket->readAll();
        QJsonDocument jsonDocument = QJsonDocument::fromJson(data.toUtf8());
        QVariant variant = jsonDocument.toVariant();
        QMap<QString, QVariant> map = variant.toMap();
        int Type = map["Type"].toInt();
        qDebug()<<data;
        if(Type==FILE_INFO_TYPE){
            User = map["User"].toString();
            is_dow=true;
            fileInfoRead(FileTcpSocket,map);
        }else if(Type==FILE_OK_TYPE){
            ToServerFileData(FileTcpSocket);
        }else if(Type==FILE_RECEIVE_OK_TYPE){
            emit receive();
        }
    });
    if(!FileTcpSocket->waitForConnected(2*1000)) {
        qDebug()<<"error!";
        return;
    }
}

/*发送文件*/
void FileThread::ToServerFileInfo(QTcpSocket *socket){
    //获取文件数据，准备发送
    QPair<QString,qint64>  DataInfoBlock = getFileContent(ServerFilePath);
    QByteArray data=(QString(R"({
                             "Type":%1,
                             "Sender":"%2",
                             "User":"%3",
                             "Data":"",
                             "FileName":"%4",
                             "FileSize":%5
                             })").arg(FILE_INFO_TYPE).arg(UserName).arg(ToUserName).arg(DataInfoBlock.first).arg(DataInfoBlock.second)).toUtf8();
    QThread::msleep(10); //添加延时
    m_fileInfoWriteBytes = socket->write(data) - typeMsgSize;
    qDebug()<< "传输文件信息，大小："<< m_sendFileSize;
    //等待发送完成，才能继续下次发送，否则发送过快，对方无法接收
    if(!socket->waitForBytesWritten(10*1000)) {
        qDebug()<<(QString("网络请求超时,原因：%1").arg(socket->errorString()));
        return;
    }

    qDebug()<<(QString("文件信息发送完成，开始对[%1]进行文件传输------------------")
                        .arg(socket->localAddress().toString()));
    qDebug()<<"当前文件传输线程id:"<<QThread::currentThreadId();

    m_localFile.setFileName(m_sendFilePath);
    if(!m_localFile.open(QFile::ReadOnly)){
        qDebug()<<(QString("文件[%1]打开失败！").arg(m_sendFilePath));
        return;
    }
}
void FileThread::ToServerFileData(QTcpSocket *socket)
{

    qint64 payloadSize = 64 * 1024 * 2; //每一帧发送1024*64个字节，控制每次读取文件的大小，从而传输速度

    double progressByte= 0;//发送进度
    qint64 bytesWritten=0;//已经发送的字节数

    while(bytesWritten != m_sendFileSize) {
        int  progress = static_cast<int>(bytesWritten/1.0/m_sendFileSize*100);
        if(bytesWritten<m_sendFileSize){
            QByteArray DataInfoBlock = m_localFile.read(qMin(m_sendFileSize,payloadSize));
            qint64 WriteBolockSize = socket->write(DataInfoBlock, DataInfoBlock.size());
            QThread::usleep(3); //添加延时，防止服务端发送文件帧过快，否则发送过快，客户端接收不过来，导致丢包
            //等待发送完成，才能继续下次发送，
            if(!socket->waitForBytesWritten(3*1000)) {
                qDebug()<<("网络请求超时");
                return;
            }
            bytesWritten += WriteBolockSize;
        }


        if(bytesWritten==m_sendFileSize){
            //LogWrite::LOG_DEBUG(QString("当前更新进度：100%,发送总次数:%1").arg(count), "server_"+socket->localAddress().toString());
            qDebug()<<(QString("当前上传进度：%1/%2 -> %3%").arg(bytesWritten).arg(m_sendFileSize).arg(progress));
            qDebug()<<(QString("-------------对[%1]的文件传输完成！------------------").arg(socket->peerAddress().toString()));
            m_localFile.close();
            return;
        }
        if(bytesWritten > m_sendFileSize) {
            qDebug()<<("意外情况！！！");
            return;
        }

        if(bytesWritten/1.0/m_sendFileSize > progressByte) {
            qDebug()<<(QString("当前上传进度：%1/%2 -> %3%").arg(bytesWritten).arg(m_sendFileSize).arg(progress));
            progressByte+=0.1;
        }
    }
}
QPair<QString,qint64> FileThread::getFileContent(QString filePath)
{
    if(!QFile::exists(filePath)) {
        qDebug()<<(QString("没有要传输的文件！" + filePath));
        return {};
    }
    m_sendFilePath = filePath;
    qDebug()<<(QString("正在获取文件信息[%1]......").arg(filePath));
    QFileInfo info(filePath);

    //获取要发送的文件大小
    m_sendFileSize = info.size();

    qDebug()<<(QString("要发送的文件大小：%1字节，%2M").arg(m_sendFileSize).arg(m_sendFileSize/1024/1024.0));

    //获取发送的文件名
    QString currentFileName=filePath.right(filePath.size()-filePath.lastIndexOf('/')-1);

    qDebug()<<(QString("文件[%1]信息获取完成！").arg(currentFileName));
    //发送的文件总大小中，信息类型不计入
    QString msg;
    if(m_sendFileSize>1024*1024) {
        msg = QString("%1M").arg(m_sendFileSize/1024/1024.0);
    }
    else {
        msg = QString("%1KB").arg(m_sendFileSize/1024.0);
    }
    qDebug()<<(QString("发送的文件名：%1，文件大小：%2").arg(currentFileName).arg(msg));

    return {currentFileName,m_sendFileSize};
}

/*接收文件*/
void FileThread::fileInfoRead(QTcpSocket *socket,QMap<QString, QVariant> map)
{
    qDebug()<<"文件信息读取on_fileInfoRead......";
    // 接收文件大小，数据总大小信息和文件名大小,文件名信息
    serverFile->fileName = map["FileName"].toString();
    serverFile->fileSize = map["FileSize"].toInt();
    // 获取文件名，建立文件
    qDebug()<<(QString("Client下载文件 %1, 文件大小：%2").arg(serverFile->fileName).arg(serverFile->fileSize));
    filePath = m_downloadPath + "/" + serverFile->fileName;
    serverFile->localFile.setFileName(filePath);
    if(serverFile->fileSize>1024*1024) {
        getServerFileSize = QString("%1M").arg(serverFile->fileSize/1024/1024.0);
    }
    else {
        getServerFileSize = QString("%1KB").arg(serverFile->fileSize/1024.0);
    }

    // 打开文件，准备写入
    if(!serverFile->localFile.open(QIODevice::WriteOnly)) {
        qDebug()<<"文件打开失败！";
    }
    //文件信息获取完成，接着获取文件数据
    QByteArray senddata=(QString(R"({
                             "Type":%1
                             })").arg(FILE_OK_TYPE)).toUtf8();
    socket->write(senddata);
    QThread::msleep(10); //添加延时
    qDebug()<< "传输文件信息，大小："<< m_sendFileSize;
    //等待发送完成，才能继续下次发送，否则发送过快，对方无法接收
    if(!socket->waitForBytesWritten(10*1000)) {
        qDebug()<<(QString("网络请求超时,原因：%1").arg(socket->errorString()));
        return;
    }
}
void FileThread::fileDataRead(QTcpSocket *socket)
{
    qint64 readBytes = socket->bytesAvailable();
    if(readBytes <0) return;
    int progress = 0;
    // 如果接收的数据大小小于要接收的文件大小，那么继续写入文件
    if(serverFile->bytesReceived < serverFile->fileSize) {
        // 返回等待读取的传入字节数
        QByteArray data = socket->read(readBytes);
        qint64 size = data.size();
        serverFile->bytesReceived+=size;
        qDebug()<<(QString("接收进度：%1/%2(字节)").arg(serverFile->bytesReceived).arg(serverFile->fileSize));
        progress =static_cast<int>(serverFile->bytesReceived*100/serverFile->fileSize);
        serverFile->progressByte = serverFile->bytesReceived;
        serverFile->progressStr = QString("%1").arg(progress);
        serverFile->localFile.write(data);
    }

    // 接收数据完成时
    if (serverFile->bytesReceived==serverFile->fileSize){
        qDebug()<<(tr("接收文件[%1]成功！").arg(serverFile->fileName));
        progress = 100;
        serverFile->localFile.close();
        qDebug()<<(QString("接收进度：%1/%2（字节）").arg(serverFile->bytesReceived).arg(serverFile->fileSize));
        serverFile->progressByte = serverFile->bytesReceived;
        serverFile->initReadData();
        QByteArray data=(QString(R"({
                                 "Type":%1
                                 })").arg(FILE_RECEIVE_OK_TYPE)).toUtf8();
        socket->write(data);
        QThread::msleep(10); //添加延时
        qDebug()<< "传输文件信息，大小："<< m_sendFileSize;
        //等待发送完成，才能继续下次发送，否则发送过快，对方无法接收
        if(!socket->waitForBytesWritten(10*1000)) {
            qDebug()<<(QString("网络请求超时,原因：%1").arg(socket->errorString()));
            return;
        }
        emit FilePath(filePath,getServerFileSize);
        is_dow=false;
        if(!file.empty()){
            ServerFilePath=file.front();
            file.pop();
            ToServerFileInfo(FileTcpSocket);
        }
    }
}

void FileThread::getPath(QString path){
    if(is_dow){//防止在文件还未接收完全时再次上传文件导致文件丢失
        file.push(path);
        return;
    }
    ServerFilePath=path;
    ToServerFileInfo(FileTcpSocket);
}

void FileThread::run(){
    FileSocketInit();
    exec();
}
